package com.ytktt.study.week8.task6.hmily.tcc.order.service.impl;

import com.ytktt.study.week8.task6.hmily.tcc.account.api.AccountService;
import com.ytktt.study.week8.task6.hmily.tcc.account.dto.AccountDTO;
import com.ytktt.study.week8.task6.hmily.tcc.account.dto.AccountNestedDTO;
import com.ytktt.study.week8.task6.hmily.tcc.account.entity.AccountEntity;
import com.ytktt.study.week8.task6.hmily.tcc.order.entity.OrderEntity;
import com.ytktt.study.week8.task6.hmily.tcc.order.mapper.OrderMapper;
import com.ytktt.study.week8.task6.hmily.tcc.order.service.PaymentService;
import com.ytktt.study.week8.task6.hmily.tcc.stock.api.ItemStockService;
import com.ytktt.study.week8.task6.hmily.tcc.stock.dto.ItemStockDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.stereotype.Service;

/**
 * TODO
 *
 * @author ytk
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {

    private final OrderMapper orderMapper;
    private final AccountService accountService;
    private final ItemStockService itemStockService;

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public void makePayment(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.payment(this.buildAccountDTO(entity));
        this.itemStockService.decrease(this.buildItemStockDTO(entity));
    }

    @Override
    public void testMakePayment(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.testPayment(this.buildAccountDTO(entity));
        this.itemStockService.testDecrease(this.buildItemStockDTO(entity));
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public void makePaymentWithNested(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        AccountEntity accountEntity = this.accountService.getByUserId(entity.getUserId());
        if (accountEntity.getBalance().compareTo(entity.getOrderPrice()) <= 0) {
            throw new IllegalArgumentException("余额不足");
        }
        this.accountService.paymentWithNested(this.buildAccountNestedDTO(entity));
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public void makePaymentWithNestedException(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        AccountEntity accountEntity = this.accountService.getByUserId(entity.getUserId());
        if (accountEntity.getBalance().compareTo(entity.getOrderPrice()) <= 0) {
            throw new IllegalArgumentException("余额不足");
        }
        this.accountService.paymentWithNestedException(this.buildAccountNestedDTO(entity));
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public String mockPaymentItemStockWithTryException(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.payment(this.buildAccountDTO(entity));
        this.itemStockService.mockWithTryException(this.buildItemStockDTO(entity));
        return "success";
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public String mockPaymentItemStockWithTryTimeout(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.payment(this.buildAccountDTO(entity));
        this.itemStockService.mockWithTryTimeout(this.buildItemStockDTO(entity));
        return "success";
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public String mockPaymentAccountWithTryException(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.mockTryPaymentException(this.buildAccountDTO(entity));
        return "success";
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public String mockPaymentAccountWithTryTimeout(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.mockTryPaymentTimeout(this.buildAccountDTO(entity));
        return "success";
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
    public String mockPaymentItemStockWithConfirmTimeout(OrderEntity entity) {
        this.updateOrderStatus(entity, 3);
        this.accountService.payment(this.buildAccountDTO(entity));
        this.itemStockService.mockWithConfirmTimeout(this.buildItemStockDTO(entity));
        return "success";
    }

    public void confirmOrderStatus(OrderEntity entity) {
        this.updateOrderStatus(entity, 1);
        log.info("=========进行订单confirm操作完成================");
    }

    public void cancelOrderStatus(OrderEntity entity) {
        this.updateOrderStatus(entity, 0);
        log.info("=========进行订单cancel操作完成================");
    }

    private void updateOrderStatus(OrderEntity entity, int orderStatus) {
        entity.setStatus((byte) orderStatus);
        this.orderMapper.updateByPrimaryKeySelective(entity);
    }

    private AccountDTO buildAccountDTO(OrderEntity entity) {
        AccountDTO accountDTO = new AccountDTO();
        accountDTO.setPayAmount(entity.getOrderPrice());
        accountDTO.setUserId(entity.getUserId());
        return accountDTO;
    }

    private AccountNestedDTO buildAccountNestedDTO(OrderEntity entity) {
        AccountNestedDTO nestedDTO = new AccountNestedDTO();
        nestedDTO.setPayAmount(entity.getOrderPrice());
        nestedDTO.setUserId(entity.getUserId());
        nestedDTO.setItemId(entity.getItemId());
        nestedDTO.setItemAmount(entity.getAmount());
        return nestedDTO;
    }

    private ItemStockDTO buildItemStockDTO(OrderEntity entity) {
        ItemStockDTO itemStockDTO = new ItemStockDTO();
        itemStockDTO.setAmount(entity.getAmount());
        itemStockDTO.setItemId(entity.getItemId());
        return itemStockDTO;
    }
}
